package baseFx.database;

import baseFx.common.Action1T;
import baseFx.common.Dynamic;
import baseFx.common.Stream;
import baseFx.common.utils.ClassUtils;
import baseFx.common.utils.ConvertUtils;

import java.util.*;

public class SqlParam {
    public String command;
    public Map<String, Object> args = new LinkedHashMap<>();
    public Integer timeout;
    public boolean isProc = false;

    public SqlParam() {

    }

    public SqlParam(String command) {
        this.command = command;
    }

    public final <T> List<T> convert(Class<T> clazz, List<Map<?, ?>> rows) {
        if (clazz == Dynamic.class) {
            List<T> list = new ArrayList<>();
            for (Map<?, ?> item : rows) {
                list.add((T) new Dynamic(item));
            }
            return list;
        }
        return onConvert(clazz, rows);
    }

    protected <T> List<T> onConvert(Class<T> clazz, List<Map<?, ?>> data) {
        List<T> list = new ArrayList<>();
        List<Map<?, ?>> rows = Stream.create(data).toList(i -> i != null);
        if (rows.size() < 1) {
            return list;
        }
        boolean isNav = clazz.isPrimitive() || clazz == Date.class || clazz.isEnum() || clazz.getCanonicalName().startsWith("java.lang.");
        if (isNav) {
            for (Map<?, ?> row : rows) {
                list.add(ConvertUtils.change(row.values().iterator().next(), clazz));
            }
        } else {
            DbEntity entity = DbEntity.get(clazz);
            for (Map<?, ?> row : rows) {
                T model = ClassUtils.newInstance(clazz);
                for (Object item : row.keySet()) {
                    Object value = row.get(item);
                    if (value == null) {
                        continue;
                    }
                    DbEntity.DbField field = entity.getFieldByColumnName(item.toString());
                    if (field == null) {
                        continue;
                    }
                    field.set(model, ConvertUtils.change(value, field.type));
                }
                list.add(model);
            }
        }
        return list;
    }

    public static SqlParam createFor(String sql) {
        return createFor(sql, null, false);
    }

    public static SqlParam createFor(String sql, Object param, boolean isProc) {
        return createFor(sql, param, isProc, null);
    }

    public static SqlParam createFor(String sql, Object param, boolean isProc, Integer timeout) {
        SqlParam sp = new SqlParam();
        sp.command = sql;
        sp.isProc = isProc;
        sp.timeout = timeout;
        if (param instanceof Map) {
            sp.args.putAll((Map<? extends String, ?>) param);
        } else if (param instanceof Dynamic) {
            sp.args.putAll(((Dynamic) param).toMap());
        } else if (param != null) {
            sp.args.putAll(new Dynamic(param).toMap());
        }
        return sp;
    }

    public static Map<String, Object> createArgs(Action1T<Map<String, Object>> action) {
        Map<String, Object> map = new HashMap<>(4);
        action.execute(map);
        return map;
    }
}
